/*
 * Copyright (C) 2009 Jeffrey Palm
 */

/*
 * INPUT:
 * BASE_DIR - relative path to the top so that BASE_DIR + 'img' is
 *            the directory containing the images
 */

// ---------- Globals ----------

/** Google map */
var map;
/** Base URL */
var base;
/** Maps days to events for the table */
var days2Events = $H();

/** List of locations for which we've already searched. */
var addresses2gpoints = $H();

// ---------- Constants ----------
var ZOOM_VALUE = 15;
var REALLY_ZOOM_VALUE = 19;
var DAYS = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];
var MAX_NUM_MINUTES_FOR_IPHONE = 4*60;

/** Urgent time */
var URGENT = 25;

var markers = [];

// Animation variables
var animatingDay  = false;
var animatingWeek = false;
var ANIMATE_PERIOD_MILLIS = .25 * 1000;


/**
 * @param q optional query
 */
function onLoad(q) {

  base = (document.location+'').replace(/\/[^\/]*$/, '');
  var m = document.getElementById("map");

  if (m) {
    map = new GMap2(m);
    map.addControl(new GLargeMapControl());
    map.addControl(new GMapTypeControl());

    
    try {
      var lat = LATITUDE_START;  // map.php
      var lng = LONGITUDE_START; // map.php
      var scale = 12;
      map.setCenter(new GLatLng(lat,lng),scale);
    } catch (e) { /* if it's not defined for some reason */ }
    
    resetDatePicker();
  } else {
    
  }
  
  readXML(q);
}

/**
 * @param q optional query
 */
function readXML(q) {
  var url = base + '/data.xml';
  start('Looking up events');
  params = q ? {q:q} : {}
	new Ajax.Request (url,
										{   method: 'get',
												parameters: params,
												onSuccess: function(r) {loadXML(r.responseXML);},
												onError: function(e) {safeAlert(e);}
												});


}

/** Returns the innerHTML of the unique child of 'node' with node name 'name'. */
function getChildText(node,name) {
  return node.getElementsByTagName(name)[0].innerHTML;
}

function loadXML(xml) {
  done();
  var events = xml.getElementsByTagName("event");
  
  // ===============================================================================
  // TODO: Change for new york from 'meeting' and 'meetings' to 'event' and 'events'
  // ===============================================================================
  if (!events || events.length == 0) {
    events = xml.getElementsByTagName("meeting");
  }
  start('Parsing ' + events.length + ' events');
  outer: for (var i=0; i<events.length; i++) {
    var event = events[i];
    var title = event.getAttribute('title');
    var description = event.getAttribute('description');
    if (!description) description = title;
    var address = event.getAttribute('address');
    start('Looking at ' + address);
    var lat = event.getAttribute('latitude');
    var lng = event.getAttribute('longitude');
    var m = {
      'title'          : title,
      'description'    : description,
      'address'        : address,
      'lat'            : lat,
      'lng'            : lng
    };
    for (var j=0; j<event.childNodes.length; j++) {
      var date = event.childNodes[j];
      if (date.nodeName != 'date') continue;
      var day = date.getAttribute('day');
      var time = date.getAttribute('time');
      var type = date.getAttribute('type');
      var d = {
        'event'   :  m,
        'day'     :  day,
        'time'    :  time,
        'type'    :  type
      };
      lst = days2Events[day];
      if (!lst) lst = new Array();
      lst.push(d);
      days2Events[day] = lst;
    }
    done('Done with ' + address);
  }
  done();
  resetMarkers();
  //
  // Now possibly animate by day or week
  //
  if (ONLOAD_ANIMATE_DAY) {
    startAnimatingDay();
  } else if (ONLOAD_ANIMATE_WEEK) {
    startAnimatingWeek();
  }
}

function animateDayLoop() {
  if (!animatingDay) return;
  resetMarkers();
  var sel = $('hourSelect').selectedIndex;
  if (sel < $('hourSelect').options.length-1) {
    $('hourSelect').selectedIndex += 1;
    setTimeout('animateDayLoop()',ANIMATE_PERIOD_MILLIS);
  } else {
    alert("Done animating by day");
    stopAnimatingDay();
  }
}

function startAnimatingDay() {
  $('animateDayEl').innerHTML = em('STOP');
  $('hourSelect').selectedIndex = 0;
  animatingDay = true;
  animateDayLoop();
}

function stopAnimatingDay() {
  $('animateDayEl').innerHTML = 'day';  
  animatingDay = false;
}

function animateDay() {
  if (animatingDay) {
    stopAnimatingDay();
  } else if (animatingWeek) {
    stopAnimatingWeek();
    startAnimatingDay();
  } else {
    startAnimatingDay();
  }
}

function animateWeekLoop() {
  if (!animatingWeek) return;
  resetMarkers();
  var sel = $('hourSelect').selectedIndex;
  if (sel < $('hourSelect').options.length-1) {
    $('hourSelect').selectedIndex += 1;
    setTimeout('animateWeekLoop()',ANIMATE_PERIOD_MILLIS);
  } else {
    var daySel = $('daySelect').selectedIndex;
    if (daySel < $('daySelect').options.length-1) {
      $('daySelect').selectedIndex  += 1;
      $('hourSelect').selectedIndex  = 0;
      setTimeout('animateWeekLoop()',ANIMATE_PERIOD_MILLIS);
    } else {
      alert("Done animating by week");
      stopAnimatingWeek();
    }
  }
}

function startAnimatingWeek() {
  $('animateWeekEl').innerHTML = em('STOP');
  $('daySelect').selectedIndex = 0;
  $('hourSelect').selectedIndex = 0;
  animatingWeek = true;
  animateWeekLoop();
}

function stopAnimatingWeek() {
  $('animateWeekEl').innerHTML = 'week';  
  animatingWeek = false;
}

function animateWeek() {
  if (animatingWeek) {
    stopAnimatingWeek();
  } else if (animatingDay) {
    stopAnimatingDay();
    startAnimatingWeek();
  } else {
    startAnimatingWeek();
  }
}

function resetDatePicker() {
  var d = new Date();
  var hours = d.getHours();
  var minutes = d.getMinutes();
  var day = d.getDay();
  $('daySelect').selectedIndex = day;
  $('hourSelect').selectedIndex = Math.floor(2*hours+1);
}

function resetMarkers() {
  try {
    _resetMarkers();
  } catch (e) {safeAlert(e);}
}

function getColorFromMinutes(mins) {
  if (mins <= 120) {
    return "#007700";
  }
  if (mins <= 180) {
    return "#000077";
  }
  if (mins <= 240) {
    return "#770000";
  }

  // Don't do anything if there isn't anything special
  return null;
}

function getDay() {
  var day;
  if (!isIPhone()) {
    day = $('daySelect').options[$('daySelect').selectedIndex].innerHTML.toUpperCase();
  } else {
    var d = new Date();
    return DAYS[d.getDay()];
  }
  return day;
}

/**
 * Returns a value (0..48) inclusive, where 0 = 00:00, 1 = 00:30, 2 =
 * 01:30, ...
 */
function getHours() {
  var hours;
  if (!isIPhone()) {
    hours = parseInt($('hourSelect').options[$('hourSelect').selectedIndex].value);
  } else {
    var d = new Date();
    var h = d.getHours();
    var m = d.getMinutes();
    var res = h*2;
    if (m >= 30) res += 1;
    return res;
  }
  return hours;
}

/** 
 * Used to sort the list of instances by minutes if we're on the brick
 */
function sortByMinutes(instanceA,instanceB) {
  return getMinutesFromInstance(instanceA) - getMinutesFromInstance(instanceB);
}

function _resetMarkers() {

  if (!isIPhone()) {
    clearAllMarkers();
  }

  var day = getDay();
  var lst = days2Events[day];

  // For the iBrick sort by time ascending
  if (isIPhone()) {
    lst = lst.sort(sortByMinutes);
  }
  //
  // Find the markers that have times within 1, 2, and 3 hours from now
  // The colors are the following:
  //  HOUR  COLOR  ICON
  //  1     green  img/icong.png
  //  2     blue   img/iconb.png
  //  3     red    img/iconr.png
  //
  var hours = getHours();
  var nowHours = Math.floor(hours/2);
  var nowMinutes = hours%2 == 0 ? 0 : 30;
  var count = 0;
  start('Looking for events');
  for (var i=0; i<lst.length; i++) {
    //
    // An Instance is s
    //  - event event
    //  - String day
    //  - String type
    //  - String time (e.g.
    //
    var instance = lst[i];

    // Skip for negative ones
/*     if (getMinutesFromInstance(instance) < 0) { */
/*       continue; */
/*     } */

    if (instance.time < 0) {
      instance.time += 12*60;
    }
    var mins = getMinutesFromInstance(instance);
    if (mins >= 0) {
      if (!isIPhone()) {
        var iconName = getIconName(mins);
        if (iconName) {
          note('Found ' + (++count) + ' event' + (count==1 ? '' : 's') + '.');
          newMarker(iconName,instance);
        }
      } else {
        var ok = false;
        if (REQUEST['q']) {
          if (isIncludedInSearch(instance)) ok = true;
        } else {
          ok = mins <= MAX_NUM_MINUTES_FOR_IPHONE;
        }
        if (ok) {
          var link = createIPhoneLi(instance,true);
          //
          // Want to place this bahavior on the first node -- i.e. the
          // <a> tag, not the entire thing
          //
          link.onclick = newIPhoneEventPopup(instance);
        }
      }
    }
  }
}var printed=false;

/**
 * @param mins minutes difference
 */
function getIconName(mins) {
  var iconName = null;
  if (mins <= 2*60) {
    iconName = 'icong.png';
  } else if (mins <= 3*60) {
    iconName = 'iconb.png';
  } else if (mins <= 4*60) {
    iconName = 'iconr.png';
  }
  return iconName;
}

function newMarker(iconName,instance) {
  var icon = new GIcon(G_DEFAULT_ICON, imgDir() + "/" + iconName);
  var point = new GLatLng(instance.event.lat,instance.event.lng);
  var marker = new GMarker(point,icon);
  map.addOverlay(marker);
  markers.push(marker);
  GEvent.addListener(marker, 'click', newPopup(marker,instance));
  GEvent.addListener(marker, 'mouseover', newHoverPopup(marker,instance));
  GEvent.addListener(marker, 'mouseout', closeHoverPopup(marker));
}

function closeHoverPopup(marker) {
  marker.closeInfoWindow();
}

function clearAllMarkers() {
  while (markers.length > 0) markers.pop();
  map.clearOverlays();
}

function getMinutesFromInstance(instance) {
  var d = new Date();
  var nowHours = d.getHours();
  var nowMinutes = d.getMinutes();

  var hours = getHours();

  nowHours = hours/2;
  nowMinutes = (hours%2) * 30 - 30;


  var time = instance.time;
  var index = time.length-2;
  var timeHours = parseInt(time.substring(0,index));
  var timeMinutes = parseInt(time.substring(index));

  var mins = (60*timeHours + timeMinutes) - (60*nowHours + nowMinutes);
  return mins;
}

function popupPreview(instance) {
  
  var mins = getMinutesFromInstance(instance);

  var h = Math.floor(mins/60);
  var m = mins%60;
  var s = formatTime(instance.time) + " in ";
  var isUrgent = h<1 && m<20;
  if (isUrgent) s += '<span class="urgent">';
  if (h>0) {
    s += h + " hour";
    if (h != 1) s += "s";
  }
  if (m != 0) {
    if (h>0) s += " ";
    s += m + " minute";
    if (m != 1) s += "s";
  }
  if (isUrgent) s += '</span>';

  return s;
}

function popupBottom(instance) {
  var s = '';
  s += '<div class="mapPopupBottom">';
  s +=           googleDirectionsHref(instance);
  s += " | "   + googleCalendarHref(instance);
  s += " | "   + zoomHref(instance,ZOOM_VALUE);
  s += " | "   + zoomHref(instance,REALLY_ZOOM_VALUE);
  s += '</div>';  
  return s;
}

function newHoverPopup(marker,instance,nowHours,nowMinutes) {
  var _marker = marker;
  var _instance = instance;
  return function() {
    var content = html("<span class='popuptitle'>" 
                       + _instance.event.title + "</span><br/>" 
                       + popupPreview(_instance)
                       + br(1));
    content += br(1);
    content += popupBottom(_instance);
    _marker.openInfoWindowHtml(content);
  };
}

/** 
 * Converts kilometers to miles. 
 */
function km2miles(km) {
  return km * 0.621371192;
}

/**
 * Wraps the title in <b> tags.
 */
function wrapTitle(s) {
  return '<b>' + s + '</b>';
}

/**
 * Returns n number of <br/> tags.
 */
function br(n) {
  if (!n || n<1) n=1;
  var s = '';
  for (var i=0; i<n; i++) s += '<br/>';
  return s;
}

/**
 * Wraps in <em> tags.
 */
function em(s) {
  return '<em>' + s + '</em>';
}

/**
 * Wraps in <font color="c"> tags.
 */
function fontColor(c,s) {
  return '<font color="' + c + '">' + s + '</font>';
}

/**
 * Returns a space span.
 */
function space() {
  var el = document.createElement("span");
  el.innerHTML = ' ';
  return el;
}

function createPopupContent(instance,marker) {
  var e = instance.event;
  var content = wrapTitle(e.title);
  if (e.description) content += br() + e.description;
  if (e.address) content += br() + e.address;
  content += br(2) + "Type: " + em(instance.type);
  content += br(2) + popupPreview(instance);
  content += popupDistances(marker);
  content += br(1) + popupBottom(instance);
  return html(content);
}

function popupDistances(marker) {
  var content = '';
  var addresses = addresses2gpoints.keys();
  if (addresses.length == 0) return content;
  content += '<ul>';
  var fromPoint = marker.getLatLng();
  for (var i=0; i<addresses.length; i++) {
    var address = addresses[i];
    var destPoint = addresses2gpoints[address];
    var dist = LatLon.distHaversine(fromPoint.lat(),fromPoint.lng(),
                                    destPoint.lat(),destPoint.lng());
    content += '<li>';
    content += sprintf('%.2f miles',dist) + ' from ' + address + br(1);
    content += '</li>';
  }
  content += '</ul>';
  return content;
}

/** Has to be dynamic to get the distances in there. */
function newPopup(marker,instance) {
  var _marker = marker;
  var _instance = instance;
  return function() {
    var title = _instance.event.title;
    var description = _instance.event.description;
    var address = _instance.event.address;
    var content = createPopupContent(_instance,_marker);
    _marker.openInfoWindowHtml(content);
  };
}

/**
 * timeString is:
 *    730
 *   0730
 *   1730
 */
function formatTime(timeString) {
  var index = timeString.length-2;
  var start = parseInt(timeString.substring(0,index));
  var rest = timeString.substring(index);
  var amPm = null;
  if (start == 0) {
    start = 12;
    amPm = "AM";
  } else if (start > 12) {
    start -= 12;
    amPm = "PM";
  } else {
    amPm = "AM";
  }
  return start + ":" + rest + " " + amPm;
}

function html(txt) {
	return htmlStart() + txt + htmlEnd();
}

function htmlStart() {
	var s = "<div id='mainInfoDiv' style='max-width: 300px; text-align:left; padding: 2px; ' >";
	return s;
}

function htmlEnd() {
	return "</div>";
}


function start(str) {
  note('<em>' + str + '</em>');
}

function done(str) {
  note(str ? str : 'Done.');
}

function note(str) {
  if ($('msg')) {
    $('msg').innerHTML = str;
  }
}

function imgDir() {
  return base + "/" + BASE_DIR + "img";
}

// --------------------------------------------------
// IPhone
// --------------------------------------------------

function isIPhone() {
  return !map;
}

/**
 * Returns the class name or an IPhone menu item.  If 'hasArrow' is
 * true, we add the correct class to enable the right arrow.
 */
function pageItemClassName(hasArrow) {
  var cls = "page-item";
  if (hasArrow)  cls += " page-item-2";
  return cls;
}

function newLi(name,href) {
  var li = document.createElement("li");
  $("mainList").appendChild(li);
  var a = document.createElement("a");
  li.appendChild(a);
  if (href) {
    if (href != true) {
      a.href = href;
    } else {
      a.href = "#";
    }
    li.className = pageItemClassName(true);
  } else {
    a.href = "#";
    li.className = pageItemClassName(false);
  }
  a.title = name;
  a.innerHTML = name;
  return a;
}

function maybeHighlight(mins,s) {
  mins = parseInt(mins);
  if (mins == 0) return em(fontColor('#770000','NOW! '));
  if (mins < URGENT) return em(fontColor('#770000',s));
  return s;
}

function isIncludedInSearch(instance) {
  var event = instance.event;
  var q = REQUEST['q'].toLowerCase();
  if (event.address.toLowerCase().indexOf(q) >= 0) return true;
  if (event.title.toLowerCase().indexOf(q)   >= 0) return true;
  return false;
}

function createIPhoneLi(instance) {
  var event = instance.event;
  var mins = getMinutesFromInstance(instance);
  var prefix = maybeHighlight(mins,'[' + mins + ' mins ' + formatTime(instance.time) + '] ');
  var contents = prefix + event.title;
  var li = newLi(contents + " @ " + event.address,true);
  var c = getColorFromMinutes(mins);
  if (c) {
    li.style.color = c;
  }

  // Now add a map link
  addMapLink(createGoogleMapLink(event.lat,event.lng,instance), li, 'map');

  return li;
}

function addMapLink(href, li, title) {
  var a = document.createElement("a");
  li.parentNode.appendChild(a);
  a.innerHTML = title;                // This is
  a.style.color = '#009999';          // all a hack
  a.style.fontStyle = "italic";       // need to
  a.style.textDecoration = 'none';   // fix it!
  a.style.fontSize = '0.8em';
  a.className = pageItemClassName(false);
  a.style.clear = 'none';
  a.href = href;
}

function cgiEscape(s) {
  if (!s) return s;
  try {
    s = s.replace(/\s+/g,'+');
  } catch (e) {}
  return s;
}

function removeHTML(s){
  if (!s) return s;
  if (!s.replace) {
    alert("s="+s);return s;
  }
  try {
    s = s.replace(/&(lt|gt);/g, function (strMatch, p1){
        return (p1 == "lt")? "<" : ">";
      });
    return s.replace(/<\/?[^>]+(>|$)/g, "");
  } catch (e) {
    alert(e);
    alert("s="+s);
  }
  return s;
}


function safeAlert(s) {
  alert(removeHTML(s));
}

function createIPhonePopupContent(instance) {
    var title = instance.event.title;
    var description = instance.event.description;
    var content = title;
    if (description) content += "\n" + description;
    content += "\n\nType:" + instance.type;
    content += "\n\n" + popupPreview(instance);
    return content;
}

function newIPhoneEventPopup(_instance) {
  var instance = _instance;
  return function() {
    safeAlert(createIPhonePopupContent(instance));
  };
}

function createGoogleMapLink(lat,lng,instance) {
  var url = 'http://maps.google.com/maps';
  url += '?q=' + escape(removeHTML(instance.event.address)) + '@' + lat + ',' + lng;
  return url;
}

function googleDirectionsHref(instance) {
  return "<a href='" + createGoogleDirectionsLink(instance) + "'>Directions</a>";
}

/*
http://maps.google.com/maps?hl=en&safe=off&client=firefox-a&rls=org.mozilla:en-US:official&hs=Eas&um=1&ie=UTF-8&cid=0,0,11138174660663987705&fb=1&dq=3808+Forest+Park+Ave.,+baltimore,+md&daddr=3808+W+Forest+Park+Ave,+Baltimore,+MD+21216&geocode=3151963666485444653,39.326192,-76.681760&sa=X&oi=local_result&resnum=1&ct=directions-to
*/
function createGoogleDirectionsLink(instance) {
  var lat = instance.event.lat;
  var lng = instance.event.lng;
  var url = 'http://maps.google.com/maps';
  url += '?dq=' + escape(removeHTML(instance.event.address));
  url += '&daddr=' + escape(removeHTML(instance.event.address));
  url += '&geocode=3151963666485444653,' + lat + ',' + lng;
  url += '&oi=local_result&resnum=1&ct=directions-to';
  return url;
}

function googleCalendarHref(instance) {
  return "<a href='" + createGoogleCalendarLink(instance) + "'>Calendar</a>";
}

/*

http://www.google.com/googlecalendar/event_publisher_guide_detail.html

action=TEMPLATE
text=Brunch at Java Cafe
location=Java Cafe, San Francisco, CA
details=Try our Saturday brunch special:<br><br>French toast with fresh fruit<br><br>Yum!
dates=20060415T180000Z/20060415T190000Z
trp=true
sprop=website:http://www.javacafebrunches.com
sprop=name:Jave Cafe

 */
function createGoogleCalendarLink(instance) {
  var evt = instance.event;
  var action = 'TEMPLATE';
  var location = cgiEscape(removeHTML(evt.address));
  var text = cgiEscape(evt.title);
  var details = cgiEscape(evt.description);
  
  // assume an hour
  function pad(v) {
    return v<10 ? '0'+v : ''+v;
  }
  var d = new Date();
  var year = d.getYear();
  var month = pad(d.getMonth());
  var date = pad(d.getDate());
  var hours1 = pad(d.getHours()+0);
  var hours2 = pad(d.getHours()+1);
  var minutes = pad(d.getMinutes());
  var seconds = pad(d.getSeconds());
  var startDate = year + month + date + '15T' + hours1 + minutes + seconds;
  var endDate = year + month + date + '15T' + hours2 + minutes + seconds;

  var dates = startDate + '/' + endDate;
  var trp = 'true';
  var spropWebsite = 'website:' + document.location;
  var spropName = 'name:' + cgiEscape(evt.title);

  return 'http://www.google.com/calendar/event'
    +    '?action='   + action
    +    '&location=' + location
    +    '&text='     + text
    +    '&details='  + details
    +    '&dates='    + dates
    +    '&trp='      + trp
    +    '&sprop='    + spropWebsite
    +    '&sprop='    + spropName
    ;
}

function zoomLink(instance,amount) {
  var lat = instance.event.lat;
  var lng = instance.event.lng;
  return "map.setCenter(new GLatLng(" + lat + ", " + lng + "), " + amount + ")";
}

function zoomHref(instance,amount) {
  var res = "<a href='#' onclick='" + zoomLink(instance,amount) + "'>";
  if (amount == REALLY_ZOOM_VALUE) {
    res += "<b>";
  }
  res += "Zoom";
  if (amount == REALLY_ZOOM_VALUE) {
    res += "!</b>";
  }
  res += "</a>";
  return res;
}

function getCity() {
  return CITY;
}

function getState() {
  return STATE;
}

function doSearch() {
  var q = $('q').value;
  var url = '/geocode.php';
  start('Looking up ' + q);
  if (!q.match(/.*,.*/)) {
    q += ', ' + getCity() + ', ' + getState();
  }
  url += '?q=' + q.replace(/\s+/g,'+');
  url += '&key=' + GOOGLE_MAPS_KEY;
  url += '&output=' + 'xml';
  url += '&oe=' + 'utf8';
  url += '&sensor=' + 'false';
	new Ajax.Request (url,
										{   method: 'get',
												parameters:{},
												onSuccess: function(r) {showLocation(r.responseXML);},
												onError: function(e) {safeAlert(e); done();}
                    });  
}

function innerHTML(xml,nodeName) {
  return xml.getElementsByTagName(nodeName)[0].firstChild.nodeValue;
}

function showLocation(xml) {
  var address = innerHTML(xml,'address');
  var coordsString  = innerHTML(xml,'coordinates');
  var coords = coordsString.split(/,/);
  var lng = parseFloat(coords[0]);
  var lat = parseFloat(coords[1]);
  var point = new GLatLng(lat,lng);
  var justAddress = address.replace(/,.*/,'');
  addresses2gpoints[justAddress] = point;
  var marker = new GMarker(point);
  map.addOverlay(marker);
  var f = newLocationPopup(marker,address);
  GEvent.addListener(marker, 'click', f);
  done();
  map.panTo(point);
  f();
}

function newLocationPopup(marker,address) {
  var _marker  = marker;
  var _address = address.replace(/,\s*/,'<br/>');
  return function(e) {
    var content = html("<span class='popuptitle'>" + _address + "</span>");
    _marker.openInfoWindowHtml(content);
  };
}

// ======================================================================
// Alphabetical page
// ======================================================================

/**
 * Shows the map with link id 'id' and iframe id 'frameId'.
 */
function toggleMap(base,id,divId,frameId,lat,lng) {
  var div = $(divId);
  var iframe = $(frameId);
  if (!div || !iframe) return;
  iframe.src = base + '/small_map.php?lat=' + lat + "&lng=" + lng;
  Effect.SlideDown(div);
  var a = $(id);
  a.onclick = function() {closeMapFrame(base,id,divId,frameId,lat,lng);};
  a.innerHTML = 'hide';
}

function closeMapFrame(base,id,divId,frameId,lat,lng) {
  var div = $(divId);
  Effect.SlideUp(div);
  var a = $(id);
  a.onclick = function() {toggleMap(base,id,divId,frameId,lat,lng);};
  a.innerHTML = 'map';
}


// ======================================================================
// sprintf:
//   http://www.webtoolkit.info/javascript-sprintf.html
// ======================================================================

/**
*
*  Javascript sprintf
*  http://www.webtoolkit.info/
*
*
**/
 
sprintfWrapper = {
 
	init : function () {
 
		if (typeof arguments == "undefined") { return null; }
		if (arguments.length < 1) { return null; }
		if (typeof arguments[0] != "string") { return null; }
		if (typeof RegExp == "undefined") { return null; }
 
		var string = arguments[0];
		var exp = new RegExp(/(%([%]|(\-)?(\+|\x20)?(0)?(\d+)?(\.(\d)?)?([bcdfosxX])))/g);
		var matches = new Array();
		var strings = new Array();
		var convCount = 0;
		var stringPosStart = 0;
		var stringPosEnd = 0;
		var matchPosEnd = 0;
		var newString = '';
		var match = null;
 
		while (match = exp.exec(string)) {
			if (match[9]) { convCount += 1; }
 
			stringPosStart = matchPosEnd;
			stringPosEnd = exp.lastIndex - match[0].length;
			strings[strings.length] = string.substring(stringPosStart, stringPosEnd);
 
			matchPosEnd = exp.lastIndex;
			matches[matches.length] = {
				match: match[0],
				left: match[3] ? true : false,
				sign: match[4] || '',
				pad: match[5] || ' ',
				min: match[6] || 0,
				precision: match[8],
				code: match[9] || '%',
				negative: parseInt(arguments[convCount]) < 0 ? true : false,
				argument: String(arguments[convCount])
			};
		}
		strings[strings.length] = string.substring(matchPosEnd);
 
		if (matches.length == 0) { return string; }
		if ((arguments.length - 1) < convCount) { return null; }
 
		var code = null;
		var match = null;
		var i = null;
 
		for (i=0; i<matches.length; i++) {
 
			if (matches[i].code == '%') { substitution = '%' }
			else if (matches[i].code == 'b') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(2));
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'c') {
				matches[i].argument = String(String.fromCharCode(parseInt(Math.abs(parseInt(matches[i].argument)))));
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'd') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'f') {
				matches[i].argument = String(Math.abs(parseFloat(matches[i].argument)).toFixed(matches[i].precision ? matches[i].precision : 6));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'o') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(8));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 's') {
				matches[i].argument = matches[i].argument.substring(0, matches[i].precision ? matches[i].precision : matches[i].argument.length)
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'x') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'X') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16));
				substitution = sprintfWrapper.convert(matches[i]).toUpperCase();
			}
			else {
				substitution = matches[i].match;
			}
 
			newString += strings[i];
			newString += substitution;
 
		}
		newString += strings[i];
 
		return newString;
 
	},
 
	convert : function(match, nosign){
		if (nosign) {
			match.sign = '';
		} else {
			match.sign = match.negative ? '-' : match.sign;
		}
		var l = match.min - match.argument.length + 1 - match.sign.length;
		var pad = new Array(l < 0 ? 0 : l).join(match.pad);
		if (!match.left) {
			if (match.pad == "0" || nosign) {
				return match.sign + pad + match.argument;
			} else {
				return pad + match.sign + match.argument;
			}
		} else {
			if (match.pad == "0" || nosign) {
				return match.sign + match.argument + pad.replace(/0/g, ' ');
			} else {
				return match.sign + match.argument + pad;
			}
		}
	}
}
 
sprintf = sprintfWrapper.init;
